/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-12
 * V4.0
 */
package com.jphenix.share.tools;

import com.jphenix.standard.docs.ClassInfo;
import com.jphenix.standard.lang.IPrintStream;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;


/**
 * 将Java源代码编译成class工具
 * @author 刘虻
 * 2007-3-1上午10:05:34
 */
@ClassInfo({"2014-06-12 20:02","将Java源代码编译成class工具"})
public class JavacTool {
	
	protected IPrintStream printStream = null; //打印流
	
	/**
	 * 获取输出信息线程
	 * @author 刘虻
	 * 2007-10-26下午08:02:55
	 */
	protected class InputThread extends Thread {
		
		protected InputStream is = null; //输入流
		
		protected StringBuffer outSbf = new StringBuffer(); //输出信息
		
		/**
		 * 构造函数
		 * 2007-10-26下午08:04:20
		 */
		public InputThread(InputStream is) {
			super("JavacTool-InputThread");
			this.is = is;
		}
		
		/**
		 * 获取输出信息
		 * @author 刘虻
		 * 2007-10-26下午08:06:27
		 * @return 输出信息
		 */
		public String getOutInfo() {
			return outSbf.toString();
		}
		
		/**
		 * 覆盖方法
		 * @author 刘虻
		 * 2007-10-26下午08:05:08
		 */
		@Override
        public void run() {
			
			String outSub = null; //输出段
			//构造输出缓存
			BufferedReader bufferedReader = 
				new BufferedReader( new InputStreamReader(is));
			//循环读取
			try {
				while((outSub=bufferedReader.readLine())!=null){
					outSbf.append(outSub);
			    }
			}catch(Exception e) {
				e.printStackTrace();
				outSbf.append(e);
			}
			try {
				bufferedReader.close();
			}catch(Exception e) {
				e.printStackTrace();
				outSbf.append(e);
			}
		}
	}
	
	/**
	 * 构造函数
	 * 2007-3-1上午10:05:35
	 */
	public JavacTool() {
		super();
	}


	/**
	 * 执行编译
	 * @author 刘虻
	 * 2007-10-26下午07:33:09
	 * @param srcPath 源文件路径
	 * @param objBasePath 目标类根路径
	 * @param encoding 文件编码
	 * @param classPath 类路径
	 * @throws Exception 执行发生异常
	 */
	public void compileJavaFile(
			String srcPath
			, String objBasePath
			, String encoding
			, String classPath)
			throws Exception {
		//使用命令行方式执行编译
		compliteJavaFileWithCmd(srcPath,objBasePath,encoding,classPath);
	}
	
	
	/**
	 * 用应用程序执行编译
	 * @author 刘虻
	 * 2007-10-26下午07:46:38
	 * @param srcPath 源文件路径
	 * @param objBasePath 目标类根路径
	 * @param encoding 文件编码
	 * @param classPath 类路径
	 * @throws Exception 执行发生异常
	 */
	protected void compliteJavaFileWithCmd(
			String srcPath
			, String objBasePath
			, String encoding
			, String classPath)
			throws Exception {
		
		//默认系统类路径
		if (classPath==null) {
			classPath = System.getProperty("java.class.path");
		}
		//使用固定的UTF-8格式编码
		if (encoding==null) {
			//encoding = System.getProperty("file.encoding");
			encoding = "UTF-8";
		}
		
		//构建命令行
		StringBuffer cmdSbf = 
			new StringBuffer(getJavacBaseCmd());
		
		cmdSbf
			.append(" -nowarn -encoding ")
			.append(encoding)
			.append(" -classpath ")
			.append(classPath);
		if (objBasePath!=null) {
			cmdSbf
				.append(" -d ")
				.append(objBasePath);
		}
		cmdSbf
			.append(" ")
			.append(srcPath);

		//获取运行时类实例
		Runtime runtime = Runtime.getRuntime();
		
		System.out.println("Begin Execute:\n"+cmdSbf);
		
		//获取执行进程
		Process pos = runtime.exec(cmdSbf.toString());
		
		//构建输出信息监听线程
		InputThread normalIt = 
			new InputThread(pos.getInputStream());
		
		//构建错误信息监听线程
		InputThread errorIt = 
			new InputThread(pos.getErrorStream());
		
		errorIt.start(); //启动错误信息监听线程
		normalIt.start(); //启动普通信息监听线程
		errorIt.join(); //执行监听
		normalIt.join(); //执行监听
		
		//先获取错误信息
		String infoMsg = errorIt.getOutInfo();
		if (infoMsg.length()>0) {
			infoMsg = "Command Line:\n"+cmdSbf+"\nInfoMsg:\n"+infoMsg;
			System.err.println(infoMsg);
			throw new Exception(infoMsg);
		}
		System.out.println(normalIt.getOutInfo());
	}
	
	
	/**
	 * 获取编译命令路径
	 * @author 刘虻
	 * 2007-10-26下午07:41:32
	 * @return 编译命令路径
	 */
	protected String getJavacBaseCmd() {
		//参数中的java根 /javapath/jre
		String javaHome = System.getProperty("java.home");
		javaHome = javaHome.replaceAll("(?i)\\\\","/"); //整理路径分割符
		return javaHome.substring(0,javaHome.lastIndexOf("/"))+"/bin/javac";
	}
	
	
	/**
	 * 编译指定java文件为class文件
	 * 
	 * 此方法已经过时,因为jdk15以后,没有执行编译的方法
	 * 
	 * @author 刘虻
	 * 2007-3-1上午10:11:16
	 * @param srcPath 源文件路径
	 * @param objBasePath 目标类根路径
	 * @param encoding 编码（为空时默认系统编码）
	 * @param classPath 类路径 （为空时默认系统类路径）
	 * @throws Exception 执行发生异常
	 */
	protected void compileJavaFileV142(
						String srcPath
						, String objBasePath
						, String encoding
						, String classPath)
						throws Exception {
		//默认系统类路径
		if (classPath==null) {
			classPath = System.getProperty("java.class.path");
		}
		//使用固定的UTF-8格式编码
		if (encoding==null) {
			//encoding = System.getProperty("file.encoding");
			encoding = "UTF-8";
		}
		
		//导入参数序列
		ArrayList<String> propList = new ArrayList<String>();
		//放入参数
		propList.add("-nowarn");
		propList.add("-encoding");
		propList.add(encoding);
		propList.add("-classpath");
		propList.add(classPath);
		//打印类路径
		//System.out.println(classPath);
		if (objBasePath!=null) {
			propList.add("-d");
			propList.add(objBasePath);
		}
		propList.add(srcPath);
		
		//构造导入参数
		String[] arg0 = new String[propList.size()];
		propList.toArray(arg0);
		
		//执行编译 只有1.4.2 以前的版本支持类中编译
		//com.sun.tools.javac.Main.compile(arg0);
	}
	
	
	
}



